Ruby 日記 31日目: オブジェクトの凍結と破壊的な操作と代入
#Ruby_日記 #2021-09-27
https://rex.libertyfish.co.jp/exam_histories/42141/user_answers/6fab112b-61f9-4c4f-8c4d-85187d2663ca
次のプログラムを実行するとどうなりますか
code:gold/ex31/main.rb
array = "a", "b", "c".freeze
array = array.map!{|content| content.succ}
p array
選択肢:
["a", "b", "c"]と表示される
["A", "B", "C"]と表示される
["b", "c", "d"]と表示される
例外が発生する
解説:
.freeze した変数に対して破壊的な操作 .map! はできない。ので、正解は「例外が発生する」だね。
code:sh
# ruby gold/ex31/main.rb
gold/ex31/main.rb:2:in `map!': can't modify frozen Array (RuntimeError)
from gold/ex31/main.rb:2:in `<main>'
/icons/hr.icon
もしこの問題が、破壊的ではない操作 .map を使っていたとしたら、
code:gold/ex31/sample.rb
array = "a", "b", "c".freeze
array = array.map{|content| content.succ}
p array
code:sh
# ruby gold/ex31/sample.rb
"b", "c", "d"
エラーにならない。
これは、.freezeでは変数の代入による変化は防げないため。
詳しくは↓の通り。
/icons/hr.icon
instance method Object#freeze (Ruby 2.1.0)
オブジェクトを凍結(内容の変更を禁止)します。
凍結されたオブジェクトの変更は 例外 RuntimeError を発生させます。 いったん凍結されたオブジェクトを元に戻す方法はありません。
そうだね
凍結されるのはオブジェクトであり、変数ではありません。代入などで変数の指す オブジェクトが変化してしまうことは freeze では防げません。 freeze が防ぐのは、 `破壊的な操作' と呼ばれるもの一般です。
なるほど〜
code:rb
a1 = "foo".freeze
a1 = "bar"
p a1 #=> "bar"
ふむふむ。a1 = "bar" でエラーにならないのね
変数への参照自体を凍結したい 場合は、グローバル変数なら Kernel.#trace_var が使えます。
へ〜。module function Kernel.#trace_var (Ruby 2.1.0)
凍結を解除することはできませんが、Object#dup を使えばほぼ同じ内容の凍結されていない オブジェクトを得ることはできます。
instance method Object#clone (Ruby 2.1.0)
code:rb
a = 1.freeze
p a.frozen? #=> true
b = a.dup
p b #=> 1
p b.frozen? #=> false
そうだね〜
/icons/hr.icon
instance method Array#collect! (Ruby 2.1.0)
collect! {|item| ..} -> self
map! {|item| ..} -> self
collect! -> Enumerator
map! -> Enumerator
各要素を順番にブロックに渡して評価し、その結果で要素を 置き換えます。
ブロックが与えられなかった場合は、自身と map! から生成した Enumerator オブジェクトを返します。
code:rb
irb(main):003:0> arr = 1, 2, 3
=> 1, 2, 3
irb(main):004:0> enum = arr.map!
=> #<Enumerator: 1, 2, 3:map!>
ほ〜ん
/icons/hr.icon
instance method String#next (Ruby 2.1.0)
succ -> String
next -> String
self の「次の」文字列を返します。
「次の」文字列は、対象の文字列の右端から アルファベットなら アルファベット順(aの次はb, zの次はa, 大文字も同様)に、 数字なら 10 進数(9 の次は 0)とみなして計算されます。
"99" → "100", "AZZ" → "BAA" のような繰り上げも行われます。 このとき負符号などは考慮されません。
code:rb
p "99".succ # => "100"
p "ZZ".succ # => "AAA"
p "a9".succ # => "b0"
p "-9".succ # => "-10"
へ〜〜